#pragma once
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickFramebufferObject>
#include <QOpenGLFramebufferObject>
#include <QMetaType>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgGA/EventQueue>

struct OsgViewerWrapper : QObject {
    Q_OBJECT
    Q_PROPERTY(QObject* viewer READ viewerAsQObject CONSTANT)
public:
    osgViewer::Viewer* _viewer;
    OsgViewerWrapper(osgViewer::Viewer* v, QObject* p = nullptr) : QObject(p), _viewer(v) {}
    QObject* viewerAsQObject() const { return reinterpret_cast<QObject*>(_viewer); }
};

struct OsgFboRenderer : QQuickFramebufferObject::Renderer {
    osgViewer::Viewer* _viewer;
    bool _initialized = false;
    OsgFboRenderer(osgViewer::Viewer* v) : _viewer(v) {}
    QOpenGLFramebufferObject* createFramebufferObject(const QSize& s) override { 
        if (!_initialized) {
            _viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
            _initialized = true;
        }
        return new QOpenGLFramebufferObject(s, QOpenGLFramebufferObject::CombinedDepthStencil); 
    }
    void render() override { 
        if (!_viewer || !framebufferObject()) return;
        _viewer->getCamera()->setViewport(0, 0, framebufferObject()->width(), framebufferObject()->height());
        _viewer->frame();
    }
};

struct OsgViewerItem : QQuickFramebufferObject {
    Q_OBJECT
    Q_PROPERTY(QObject* viewer WRITE setViewer NOTIFY viewerChanged)
public:
    Renderer* createRenderer() const override { 
        return _viewer ? new OsgFboRenderer(_viewer) : nullptr; 
    }
    void setViewer(QObject* v) { 
        _viewer = reinterpret_cast<osgViewer::Viewer*>(v); 
        emit viewerChanged();
        update();
    }
signals:
    void viewerChanged();
private:
    osgViewer::Viewer* _viewer = nullptr;
};

#include <QSurfaceFormat>

inline int test3_main(int argc, char* argv[]) {
    QGuiApplication app(argc, argv);
    
    QSurfaceFormat format;
    format.setVersion(4, 6);
    format.setProfile(QSurfaceFormat::CoreProfile);
    QSurfaceFormat::setDefaultFormat(format);

    osgViewer::Viewer viewer;
    viewer.setSceneData(osgDB::readNodeFile("glsl_simple.osgt"));
    
    viewer.realize(); 

    qmlRegisterType<OsgViewerItem>("com.example", 1, 0, "OsgViewerItem");
    
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("osgViewer", new OsgViewerWrapper(&viewer));
    
    engine.load(QUrl("../test/quick/test.qml"));
    
    return app.exec();
}